#include "Sphere3D.h"
#include <cmath>
#include <limits>

namespace RayTracer
{
    Sphere3D::Sphere3D(float radius, Vector3D center, Vector3D dir) : Surface(center, dir)
    {
		this->radius = radius;
		this->radiusSq = this->radius * this->radius;
    }
		
    Vector3D Sphere3D::Normal (const Vector3D *point) const
    {
		Vector3D n = Vector3D::Subtract(point, &this->position);
		Vector3D::Normalize(&n);
		return n;
    }
		
    HitInfo Sphere3D::Hit (const Ray3D *ray, float tMin, float tMax) const
    {
		Vector3D v = Vector3D::Subtract(&ray->position, &this->position);
		float b = -DOT(v, ray->direction);
		float det = (b * b) - DOT(v, v) + this->radiusSq;
		int res = HitInfo::Miss;

		float dist = tMax - tMin;

		if (det > 0)
		{
			det = sqrtf( det );
			float i1 = b - det;
			float i2 = b + det;
			if (i2 > 0)
			{
				if (i1 < 0) 
				{
					if (i2 < dist) 
					{
						dist = i2;
						res = HitInfo::HitInside;
					}
				}
				else
				{
					if (i1 < dist)
					{
						dist = i1;
						res = HitInfo::Hit;
					}
				}
			}
		}

		Vector3D intersectionPoint = Vector3D::Add(&ray->position, &Vector3D::MultiplyN(&ray->direction, dist));
		return HitInfo((ISurface*)this, &intersectionPoint, dist, res);
    }
		
    float Sphere3D::GetRadius() const
    {
		return radius;
    }

    void Sphere3D::SetRadius(float value)
    {
		this->radius = value;
    }
};
